Load Libraries

library(tidyverse)
library(tidycensus)
library(ggrepel)

Read in the NY Times Data

# Get the NY Times data from github
countiesURL <- "https://raw.githubusercontent.com/nytimes/covid-19-data/master/us-counties.csv"
countiesData <- read_csv(url(countiesURL))
Parsed with column specification:
cols(
  date = col_date(format = ""),
  county = col_character(),
  state = col_character(),
  fips = col_character(),
  cases = col_double(),
  deaths = col_double()
)

Use Census API to get the populations of each county

# Get census API key from: https://api.census.gov/data/key_signup.html
# census_api_key("YOUR KEY GOES HERE")
census_api_key("779c8b33af41fa4dbf19a22405c65c780fd379ac")
To install your API key for use in future sessions, run this function with `install = TRUE`.
# Get population estimates per county from the US Census API
popEst <- get_estimates(geography = "county",
                        product = "population")
popEst <- popEst %>%
  filter(variable == "POP")

Join the census data with the NY Times Data

Need to fix places like NYC, etc.

# Join Data
countiesData <- left_join(countiesData, popEst, by = c("fips" = "GEOID"))
countiesData <- countiesData %>%
  filter(!is.na(value))
# Get cases and deaths per million population
countiesData <- countiesData %>%
  mutate(casesPerMillion = (cases/value)*1000000) %>%
  mutate(deathsPerMillion = (deaths/value)*1000000) 

# countiesData[which(countiesData$county == "Marin"),]

Set t = 0 to the first observed case in each county

# Add a label for the max time for each county
max_date_label <- countiesData %>%
  group_by(state, county) %>%
  summarise(max_time = max(time)) %>%
  mutate(is_label = (max_time == time)) %>%
  ungroup
Error in max_time == time : 
  comparison (1) is possible only for atomic and list types

Generate plots for some case studies (can easily scale these up)

#####################
# Raw counts
#####################
# Parameters
stateUse = "California"
minCases = 25
startDate = "2020-03-06"
endDate = "2020-03-27"
# Plot

selected_counties <- countiesData %>%
  group_by(state, county) %>%
  summarise(max_cases_per_county = max(cases)) %>%
  mutate(has_enough_cases = (max_cases_per_county > minCases)) %>%
  filter(has_enough_cases) %>%
  ungroup

countiesData <- countiesData %>%
  left_join(selected_counties, by = c("state", "county"))

Linear Scale

countiesData %>%
  filter(state == "California" & 
           date >= startDate &
           date <= endDate &
           has_enough_cases) %>%
    mutate(label = if_else(date == max(date), as.character(county), NA_character_)) %>%
  ggplot(aes(x = date, y = cases, group = county, color = county)) + 
  geom_line() + 
  geom_point() +
  geom_label_repel(aes(label = label),
                   nudge_x = 1,
                   na.rm = TRUE) +
  ggtitle(label = paste0("Cumulative Cases in Each ", stateUse, " County - Linear Plot"), subtitle = paste0("minimum each county is ",minCases," cases")) +
  xlab(paste0("Date starting: ",startDate)) +
  ylab("Cumulative Cases") +
  theme_bw(base_size = 12) +
  theme(legend.position = "none")

Log Scale

# Log scale
countiesData %>%
  filter(state == "California" & 
           date >= startDate &
           date <= endDate &
           has_enough_cases) %>%
  mutate(label = if_else(date == max(date), as.character(county), NA_character_)) %>%
  ggplot(aes(x = date, y = cases, group = county, color = county)) + 
  geom_line() + 
  geom_point() +
  geom_label_repel(aes(label = label),
                   nudge_x = 1,
                   na.rm = TRUE) +
  scale_y_continuous(trans='log10') +
  ggtitle(label = paste0("Cumulative Cases in Each ", stateUse, " County - Log Plot"), subtitle = paste0("minimum each county is ",minCases," cases")) +
  xlab(paste0("Date starting: ",startDate)) +
  ylab("Cumulative Cases") +
  theme_bw(base_size = 12) +
  theme(legend.position = "none")

Log Scale – cases per million

# Log scale
countiesData %>%
  filter(state == "California" & 
           date >= startDate &
           date <= endDate &
           has_enough_cases) %>%
  mutate(label = if_else(date == max(date), as.character(county), NA_character_)) %>%
  ggplot(aes(x = date, y = casesPerMillion, group = county, color = county)) + 
  geom_line() + 
  geom_point() +
  geom_label_repel(aes(label = label),
                   nudge_x = 1,
                   na.rm = TRUE) +
  scale_y_continuous(trans='log10') +
  ggtitle(label = paste0("Cumulative Cases Per Million in Each ", stateUse, " County - Log Plot"), subtitle = paste0("minimum each county is ",minCases," cases")) +
  xlab(paste0("Date starting: ",startDate)) +
  ylab("Cumulative Cases Per Million") +
  theme_bw(base_size = 12) +
  theme(legend.position = "none")

Log Scale – cases per million – first case, t=0

Generate an interactive map

# grab the spatial data (tigris)
# countiesUse <- unique(countiesData$fips[which(countiesData$state=="California")])
countiesUse <- unique(countiesData$county[which(countiesData$state=="California")])

tracts <- tracts(state = "California", county = countiesUse, cb = TRUE)
tracts$fips = paste0(tracts$STATEFP,tracts$COUNTYFP)

counts_merged <- geo_join(tracts, countiesData[which(countiesData$state=="California" & countiesData$date == endDate),], "fips", "fips", how = 'inner')
# there are some tracts with no land that we should exclude
counts_merged <- counts_merged[counts_merged$ALAND>0,]

popup <- paste0("County: ", counts_merged$county, "<br>", "Cases per million: ", round(counts_merged$casesPerMillion,2))
pal <- colorNumeric(
  palette = "YlGnBu",
  domain = counts_merged$casesPerMillion
)

map3<-leaflet() %>%
  addProviderTiles("CartoDB.Positron") %>%
  addPolygons(data = counts_merged, 
              fillColor = ~pal(casesPerMillion), 
              color = "#b2aeae", # you need to use hex colors
              fillOpacity = 0.7, 
              weight = 1, 
              smoothFactor = 0.2,
              popup = popup) %>%
  addLegend(pal = pal, 
            values = counts_merged$casesPerMillion, 
            position = "bottomright", 
            title = "Cases per million") 
map3
LS0tCnRpdGxlOiAiQ09WSUQtMTkgVGVzdCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICBodG1sX25vdGVib29rOiBkZWZhdWx0Ci0tLQojIyMgTG9hZCBMaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRpZHljZW5zdXMpCmxpYnJhcnkoZ2dyZXBlbCkKbGlicmFyeSh0aWdyaXMpCmxpYnJhcnkobGVhZmxldCkKYGBgCgojIyMgUmVhZCBpbiB0aGUgTlkgVGltZXMgRGF0YQpgYGB7cn0KIyBHZXQgdGhlIE5ZIFRpbWVzIGRhdGEgZnJvbSBnaXRodWIKY291bnRpZXNVUkwgPC0gImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9ueXRpbWVzL2NvdmlkLTE5LWRhdGEvbWFzdGVyL3VzLWNvdW50aWVzLmNzdiIKY291bnRpZXNEYXRhIDwtIHJlYWRfY3N2KHVybChjb3VudGllc1VSTCkpCmBgYAoKIyMjIFVzZSBDZW5zdXMgQVBJIHRvIGdldCB0aGUgcG9wdWxhdGlvbnMgb2YgZWFjaCBjb3VudHkKYGBge3J9CiMgR2V0IGNlbnN1cyBBUEkga2V5IGZyb206IGh0dHBzOi8vYXBpLmNlbnN1cy5nb3YvZGF0YS9rZXlfc2lnbnVwLmh0bWwKIyBjZW5zdXNfYXBpX2tleSgiWU9VUiBLRVkgR09FUyBIRVJFIikKY2Vuc3VzX2FwaV9rZXkoIjc3OWM4YjMzYWY0MWZhNGRiZjE5YTIyNDA1YzY1Yzc4MGZkMzc5YWMiKQoKIyBHZXQgcG9wdWxhdGlvbiBlc3RpbWF0ZXMgcGVyIGNvdW50eSBmcm9tIHRoZSBVUyBDZW5zdXMgQVBJCnBvcEVzdCA8LSBnZXRfZXN0aW1hdGVzKGdlb2dyYXBoeSA9ICJjb3VudHkiLAogICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0ID0gInBvcHVsYXRpb24iKQpwb3BFc3QgPC0gcG9wRXN0ICU+JQogIGZpbHRlcih2YXJpYWJsZSA9PSAiUE9QIikKYGBgCgojIyMgSm9pbiB0aGUgY2Vuc3VzIGRhdGEgd2l0aCB0aGUgTlkgVGltZXMgRGF0YQojIE5lZWQgdG8gZml4IHBsYWNlcyBsaWtlIE5ZQywgZXRjLgpgYGB7cn0KIyBKb2luIERhdGEKY291bnRpZXNEYXRhIDwtIGxlZnRfam9pbihjb3VudGllc0RhdGEsIHBvcEVzdCwgYnkgPSBjKCJmaXBzIiA9ICJHRU9JRCIpKQpjb3VudGllc0RhdGEgPC0gY291bnRpZXNEYXRhICU+JQogIGZpbHRlcighaXMubmEodmFsdWUpKSAjIEhlcmUgd2UgYXJlIHJlbW92aW5nIHBsYWNlcyBsaWtlIE5ZQyAtLSBuZWVkIHRvIHVwZGF0ZSB0aGlzLi4uLgojIEdldCBjYXNlcyBhbmQgZGVhdGhzIHBlciBtaWxsaW9uIHBvcHVsYXRpb24KY291bnRpZXNEYXRhIDwtIGNvdW50aWVzRGF0YSAlPiUKICBtdXRhdGUoY2FzZXNQZXJNaWxsaW9uID0gKGNhc2VzL3ZhbHVlKSoxMDAwMDAwKSAlPiUKICBtdXRhdGUoZGVhdGhzUGVyTWlsbGlvbiA9IChkZWF0aHMvdmFsdWUpKjEwMDAwMDApIApgYGAKCiMjIyBTZXQgdCA9IDAgdG8gdGhlIGZpcnN0IG9ic2VydmVkIGNhc2UgaW4gZWFjaCBjb3VudHkKYGBge3J9CiMgU2V0IHQ9MCB0byB0aGUgZGF0ZSBvZiB0aGUgZmlyc3QgY2FzZQp0aW1lX3plcm8gPC0gY291bnRpZXNEYXRhICU+JQogIGdyb3VwX2J5KHN0YXRlLCBjb3VudHkpICU+JQogIHN1bW1hcmlzZShmaXJzdF9jYXNlID0gbWluKGRhdGUpKSAlPiUKICB1bmdyb3VwCgojIFNldCBhIG5ldyBjb2x1bW4gZm9yIHRoZSB0aW1lIGVsYXBzZWQgYmV0d2VlbiB0aGUgZGF0ZSBjb2x1bW4gYW5kIHRoZSB0PTAgZGF0ZSBmb3IgZWFjaCByb3cKY291bnRpZXNEYXRhIDwtIGNvdW50aWVzRGF0YSAlPiUKICBsZWZ0X2pvaW4odGltZV96ZXJvLCBieSA9IGMoInN0YXRlIiwgImNvdW50eSIpKSAlPiUKICBtdXRhdGUodGltZSA9IGFzLm51bWVyaWMoZGF0ZSAtIGZpcnN0X2Nhc2UpKQoKIyBBZGQgYSBsYWJlbCBmb3IgdGhlIG1heCB0aW1lIGZvciBlYWNoIGNvdW50eQptYXhfZGF0ZV9sYWJlbCA8LSBjb3VudGllc0RhdGEgJT4lCiAgZ3JvdXBfYnkoc3RhdGUsIGNvdW50eSkgJT4lCiAgc3VtbWFyaXNlKG1heF90aW1lID0gbWF4KHRpbWUpKQoKY291bnRpZXNEYXRhIDwtIGNvdW50aWVzRGF0YSAlPiUKICBsZWZ0X2pvaW4obWF4X2RhdGVfbGFiZWwsIGJ5ID0gYygic3RhdGUiLCAiY291bnR5IikpCmBgYAoKIyMjIEdlbmVyYXRlIHBsb3RzIGZvciBzb21lIGNhc2Ugc3R1ZGllcyAoY2FuIGVhc2lseSBzY2FsZSB0aGVzZSB1cCkKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFJhdyBjb3VudHMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgUGFyYW1ldGVycwpzdGF0ZVVzZSA9ICJDYWxpZm9ybmlhIgptaW5DYXNlcyA9IDI1CnN0YXJ0RGF0ZSA9ICIyMDIwLTAzLTA2IgplbmREYXRlID0gIjIwMjAtMDMtMjciCiMgUGxvdAoKc2VsZWN0ZWRfY291bnRpZXMgPC0gY291bnRpZXNEYXRhICU+JQogIGdyb3VwX2J5KHN0YXRlLCBjb3VudHkpICU+JQogIHN1bW1hcmlzZShtYXhfY2FzZXNfcGVyX2NvdW50eSA9IG1heChjYXNlcykpICU+JQogIG11dGF0ZShoYXNfZW5vdWdoX2Nhc2VzID0gKG1heF9jYXNlc19wZXJfY291bnR5ID4gbWluQ2FzZXMpKSAlPiUKICBmaWx0ZXIoaGFzX2Vub3VnaF9jYXNlcykgJT4lCiAgdW5ncm91cAoKY291bnRpZXNEYXRhIDwtIGNvdW50aWVzRGF0YSAlPiUKICBsZWZ0X2pvaW4oc2VsZWN0ZWRfY291bnRpZXMsIGJ5ID0gYygic3RhdGUiLCAiY291bnR5IikpCmBgYAoKIyMjIExpbmVhciBTY2FsZQpgYGB7ciBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQpjb3VudGllc0RhdGEgJT4lCiAgZmlsdGVyKHN0YXRlID09ICJDYWxpZm9ybmlhIiAmIAogICAgICAgICAgIGRhdGUgPj0gc3RhcnREYXRlICYKICAgICAgICAgICBkYXRlIDw9IGVuZERhdGUgJgogICAgICAgICAgIGhhc19lbm91Z2hfY2FzZXMpICU+JQogICAgbXV0YXRlKGxhYmVsID0gaWZfZWxzZShkYXRlID09IG1heChkYXRlKSwgYXMuY2hhcmFjdGVyKGNvdW50eSksIE5BX2NoYXJhY3Rlcl8pKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gY2FzZXMsIGdyb3VwID0gY291bnR5LCBjb2xvciA9IGNvdW50eSkpICsgCiAgZ2VvbV9saW5lKCkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGFiZWxfcmVwZWwoYWVzKGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEsCiAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpICsKICBnZ3RpdGxlKGxhYmVsID0gcGFzdGUwKCJDdW11bGF0aXZlIENhc2VzIGluIEVhY2ggIiwgc3RhdGVVc2UsICIgQ291bnR5IC0gTGluZWFyIFBsb3QiKSwgc3VidGl0bGUgPSBwYXN0ZTAoIm1pbmltdW0gZWFjaCBjb3VudHkgaXMgIixtaW5DYXNlcywiIGNhc2VzIikpICsKICB4bGFiKHBhc3RlMCgiRGF0ZSBzdGFydGluZzogIixzdGFydERhdGUpKSArCiAgeWxhYigiQ3VtdWxhdGl2ZSBDYXNlcyIpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxMikgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgojIyMgTG9nIFNjYWxlCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CiMgTG9nIHNjYWxlCmNvdW50aWVzRGF0YSAlPiUKICBmaWx0ZXIoc3RhdGUgPT0gIkNhbGlmb3JuaWEiICYgCiAgICAgICAgICAgZGF0ZSA+PSBzdGFydERhdGUgJgogICAgICAgICAgIGRhdGUgPD0gZW5kRGF0ZSAmCiAgICAgICAgICAgaGFzX2Vub3VnaF9jYXNlcykgJT4lCiAgbXV0YXRlKGxhYmVsID0gaWZfZWxzZShkYXRlID09IG1heChkYXRlKSwgYXMuY2hhcmFjdGVyKGNvdW50eSksIE5BX2NoYXJhY3Rlcl8pKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBkYXRlLCB5ID0gY2FzZXMsIGdyb3VwID0gY291bnR5LCBjb2xvciA9IGNvdW50eSkpICsgCiAgZ2VvbV9saW5lKCkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGFiZWxfcmVwZWwoYWVzKGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEsCiAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpICsKICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9J2xvZzEwJykgKwogIGdndGl0bGUobGFiZWwgPSBwYXN0ZTAoIkN1bXVsYXRpdmUgQ2FzZXMgaW4gRWFjaCAiLCBzdGF0ZVVzZSwgIiBDb3VudHkgLSBMb2cgUGxvdCIpLCBzdWJ0aXRsZSA9IHBhc3RlMCgibWluaW11bSBlYWNoIGNvdW50eSBpcyAiLG1pbkNhc2VzLCIgY2FzZXMiKSkgKwogIHhsYWIocGFzdGUwKCJEYXRlIHN0YXJ0aW5nOiAiLHN0YXJ0RGF0ZSkpICsKICB5bGFiKCJDdW11bGF0aXZlIENhc2VzIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMjIyBMb2cgU2NhbGUgLS0gY2FzZXMgcGVyIG1pbGxpb24KYGBge3IgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0KIyBMb2cgc2NhbGUKY291bnRpZXNEYXRhICU+JQogIGZpbHRlcihzdGF0ZSA9PSAiQ2FsaWZvcm5pYSIgJiAKICAgICAgICAgICBkYXRlID49IHN0YXJ0RGF0ZSAmCiAgICAgICAgICAgZGF0ZSA8PSBlbmREYXRlICYKICAgICAgICAgICBoYXNfZW5vdWdoX2Nhc2VzKSAlPiUKICBtdXRhdGUobGFiZWwgPSBpZl9lbHNlKGRhdGUgPT0gbWF4KGRhdGUpLCBhcy5jaGFyYWN0ZXIoY291bnR5KSwgTkFfY2hhcmFjdGVyXykpICU+JQogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBjYXNlc1Blck1pbGxpb24sIGdyb3VwID0gY291bnR5LCBjb2xvciA9IGNvdW50eSkpICsgCiAgZ2VvbV9saW5lKCkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGFiZWxfcmVwZWwoYWVzKGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEsCiAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpICsKICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9J2xvZzEwJykgKwogIGdndGl0bGUobGFiZWwgPSBwYXN0ZTAoIkN1bXVsYXRpdmUgQ2FzZXMgUGVyIE1pbGxpb24gaW4gRWFjaCAiLCBzdGF0ZVVzZSwgIiBDb3VudHkgLSBMb2cgUGxvdCIpLCBzdWJ0aXRsZSA9IHBhc3RlMCgibWluaW11bSBlYWNoIGNvdW50eSBpcyAiLG1pbkNhc2VzLCIgY2FzZXMiKSkgKwogIHhsYWIocGFzdGUwKCJEYXRlIHN0YXJ0aW5nOiAiLHN0YXJ0RGF0ZSkpICsKICB5bGFiKCJDdW11bGF0aXZlIENhc2VzIFBlciBNaWxsaW9uIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMjIyBMb2cgU2NhbGUgLS0gY2FzZXMgcGVyIG1pbGxpb24gLS0gZmlyc3QgY2FzZSwgdD0wCmBgYHtyIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9CiMgTG9nIHNjYWxlCmNvdW50aWVzRGF0YSAlPiUKICBmaWx0ZXIoc3RhdGUgPT0gIkNhbGlmb3JuaWEiICYgCiAgICAgICAgICAgaGFzX2Vub3VnaF9jYXNlcykgJT4lCiAgbXV0YXRlKGxhYmVsID0gaWZfZWxzZSh0aW1lID09IG1heF90aW1lLCBhcy5jaGFyYWN0ZXIoY291bnR5KSwgTkFfY2hhcmFjdGVyXykpICU+JQogIGdncGxvdChhZXMoeCA9IHRpbWUsIHkgPSBjYXNlc1Blck1pbGxpb24sIGdyb3VwID0gY291bnR5LCBjb2xvciA9IGNvdW50eSkpICsgCiAgZ2VvbV9saW5lKCkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGFiZWxfcmVwZWwoYWVzKGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDEsCiAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpICsKICBzY2FsZV95X2NvbnRpbnVvdXModHJhbnM9J2xvZzEwJykgKwogIGdndGl0bGUobGFiZWwgPSBwYXN0ZTAoIkN1bXVsYXRpdmUgQ2FzZXMgUGVyIE1pbGxpb24gaW4gRWFjaCAiLCBzdGF0ZVVzZSwgIiBDb3VudHkgLSBMb2cgUGxvdCIpLCBzdWJ0aXRsZSA9IHBhc3RlMCgibWluaW11bSBlYWNoIGNvdW50eSBpcyAiLG1pbkNhc2VzLCIgY2FzZXMiKSkgKwogIHhsYWIoIlRpbWUgU2luY2UgRmlyc3QgQ2FzZSIpICsKICB5bGFiKCJDdW11bGF0aXZlIENhc2VzIFBlciBNaWxsaW9uIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMjIyBHZW5lcmF0ZSBhbiBpbnRlcmFjdGl2ZSBtYXAKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBUaGlzIGlzIGJhc2VkIG9mIG9mZiB0aGUgdHV0b3JpYWwgaGVyZTogaHR0cDovL3pldnJvc3MuY29tL2Jsb2cvMjAxNS8xMC8xNC9tYW5pcHVsYXRpbmctYW5kLW1hcHBpbmctdXMtY2Vuc3VzLWRhdGEtaW4tci11c2luZy10aGUtYWNzLXRpZ3Jpcy1hbmQtbGVhZmxldC1wYWNrYWdlcy0zLwoKIyBncmFiIHRoZSBzcGF0aWFsIGRhdGEgKHRpZ3JpcykKIyBHZXQgdGhlIGNvdW50aWVzIG9mIGludGVyZXN0CmNvdW50aWVzVXNlIDwtIHVuaXF1ZShjb3VudGllc0RhdGEkY291bnR5W3doaWNoKGNvdW50aWVzRGF0YSRzdGF0ZT09IkNhbGlmb3JuaWEiKV0pCgojIE1hcCB0aGUgY291bnRpZXMgdG8gdGhlIHNwYXRpYWwgZGF0YQp0cmFjdHMgPC0gdHJhY3RzKHN0YXRlID0gIkNhbGlmb3JuaWEiLCBjb3VudHkgPSBjb3VudGllc1VzZSwgY2IgPSBUUlVFKQp0cmFjdHMkZmlwcyA9IHBhc3RlMCh0cmFjdHMkU1RBVEVGUCx0cmFjdHMkQ09VTlRZRlApCgojIEpvaW4gb3VyIGRhdGEgZnJhbWUgd2l0aCB0aGUgY291bnRzIGRhdGEgdG8gdGhlIHNwYXRpYWwgZGF0YQpjb3VudHNfbWVyZ2VkIDwtIGdlb19qb2luKHRyYWN0cywgY291bnRpZXNEYXRhW3doaWNoKGNvdW50aWVzRGF0YSRzdGF0ZT09IkNhbGlmb3JuaWEiICYgY291bnRpZXNEYXRhJGRhdGUgPT0gZW5kRGF0ZSksXSwgImZpcHMiLCAiZmlwcyIsIGhvdyA9ICdpbm5lcicpCiMgdGhlcmUgYXJlIHNvbWUgdHJhY3RzIHdpdGggbm8gbGFuZCB0aGF0IHdlIHNob3VsZCBleGNsdWRlCmNvdW50c19tZXJnZWQgPC0gY291bnRzX21lcmdlZFtjb3VudHNfbWVyZ2VkJEFMQU5EPjAsXQoKIyBTZXR1cCB0aGUgcG9wLXVwIHRoYXQgY29tZXMgdXAgd2hlbiBob3ZlcmluZwpwb3B1cCA8LSBwYXN0ZTAoIkNvdW50eTogIiwgY291bnRzX21lcmdlZCRjb3VudHksICI8YnI+IiwgIkNhc2VzIHBlciBtaWxsaW9uOiAiLCByb3VuZChjb3VudHNfbWVyZ2VkJGNhc2VzUGVyTWlsbGlvbiwyKSkKcGFsIDwtIGNvbG9yTnVtZXJpYygKICBwYWxldHRlID0gIllsR25CdSIsCiAgZG9tYWluID0gY291bnRzX21lcmdlZCRjYXNlc1Blck1pbGxpb24KKQoKIyBQbG90IGV2ZXJ5dGhpbmcKbWFwMzwtbGVhZmxldCgpICU+JQogIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIuUG9zaXRyb24iKSAlPiUKICBhZGRQb2x5Z29ucyhkYXRhID0gY291bnRzX21lcmdlZCwgCiAgICAgICAgICAgICAgZmlsbENvbG9yID0gfnBhbChjYXNlc1Blck1pbGxpb24pLCAKICAgICAgICAgICAgICBjb2xvciA9ICIjYjJhZWFlIiwgIyB5b3UgbmVlZCB0byB1c2UgaGV4IGNvbG9ycwogICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC43LCAKICAgICAgICAgICAgICB3ZWlnaHQgPSAxLCAKICAgICAgICAgICAgICBzbW9vdGhGYWN0b3IgPSAwLjIsCiAgICAgICAgICAgICAgcG9wdXAgPSBwb3B1cCkgJT4lCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgCiAgICAgICAgICAgIHZhbHVlcyA9IGNvdW50c19tZXJnZWQkY2FzZXNQZXJNaWxsaW9uLCAKICAgICAgICAgICAgcG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLCAKICAgICAgICAgICAgdGl0bGUgPSAiQ2FzZXMgcGVyIG1pbGxpb24iKSAKbWFwMwpgYGAKCgoKCg==